package projects

import (
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/core/logs"
	beego "github.com/beego/beego/v2/server/web"
	"github.com/jinzhu/copier"
	"strconv"
	"time"
	"xpms/app/auth/users"
	"xpms/app/dict"
	"xpms/app/models"
	"xpms/cores"
	"xpms/cores/utils"
)

type ProjectsTask struct {
	Id                int64 `orm:"pk;column(taskid);" json:"Id,string"`
	Needsid           int64 `json:"Needsid,string"`
	Projectid         int64 `json:"Projectid,string"`
	Userid            int64 `json:"Userid,string"`
	Acceptid          int64 `json:"Acceptid,string"`
	Ccid              string
	Completeid        int64 `json:"Completeid,string"`
	Name              string
	Desc              string
	Acceptance        string
	Type              int
	Level             int
	Tasktime          int
	Started           int64
	Ended             int64
	Attachment        string
	Created           int64
	Changed           int64
	Status            int
	Closeid           int64 `json:"Closeid,string"`
	Cancelid          int64 `json:"Cancelid,string"`
	Testid            int64 `json:"Testid,string"`
	Moduleid          int64 `json:"Moduleid,string"`
	Actualstarttime   int64
	Actualendtime     int64
	Stage             int
	Parenttaskid      int64 `json:"Parenttaskid,string"`
	Planid            int64 `json:"Planid,string"`
	Classify          int   `json:"Classify,string"`
	Progress          int
	Remaindertasktime int
	Groupid           int64 `json:"Groupid,string"`
	Orders            int
}

type ProjectsAllTask struct {
	Id                int64 `json:"Id,string"`
	Needsid           int64 `json:"Needsid,string"`
	Needsname         string
	Projectid         int64 `json:"Projectid,string"`
	Projectname       string
	Userid            int64 `json:"Userid,string"`
	Userrealname      string
	Acceptid          int64 `json:"Acceptid,string"`
	Acceptrealname    string
	Ccid              string
	Completeid        int64 `json:"Completeid,string"`
	Completerealname  string
	Name              string
	Desc              string
	Acceptance        string
	Type              int
	Level             int
	Tasktime          int
	Started           int64
	Ended             int64
	Attachment        string
	Created           int64
	Changed           int64
	Status            int
	Closeid           int64 `json:"Closeid,string"`
	Cancelid          int64 `json:"Cancelid,string"`
	Testid            int64 `json:"Testid,string"`
	Testname          string
	Moduleid          int64 `json:"Moduleid,string"`
	Modulename        string
	Actualstarttime   int64
	Actualendtime     int64
	Stage             int
	Parenttaskid      int64 `json:"Parenttaskid,string"`
	Planid            int64 `json:"Planid,string"`
	Children          []ProjectsAllTask
	Classify          int `json:"Classify,string"`
	Related           []ProjectTaskRelatedVo
	Tasktimes         []ProjectsTaskTimeAll
	Progress          int
	Remaindertasktime int
	Groupid           int64 `json:"Groupid,string"`
	Positionid        int64 `json:"Positionid,string"`
	Positionname      string
	Orders            int
}

type ProjectsTaskLog struct {
	Id      int64 `orm:"pk;" json:"Id,string"`
	Taskid  int64 `json:"Taskid,string"`
	Userid  int64 `json:"Userid,string"`
	Note    string
	Status  int
	Created int64
}

func (this *ProjectsTask) TableName() string {
	return models.TableName("projects_task")
}

func (this *ProjectsTaskLog) TableName() string {
	return models.TableName("projects_task_log")
}
func init() {
	orm.RegisterModel(new(ProjectsTask), new(ProjectsTaskLog))
}

func AddTask(UserUsername string, upd ProjectsTask) error {
	o := orm.NewOrm()
	task := new(ProjectsTask)
	copier.Copy(task, upd)
	task.Orders = taskMaxOrder(upd) + 1
	if upd.Parenttaskid > 0 {
		task.Groupid = upd.Id
	}
	task.Status = 1
	if upd.Started < 0 {
		upd.Started = time.Now().Unix()
	}
	task.Created = time.Now().Unix()
	task.Changed = time.Now().Unix()
	_, err := o.Insert(task)
	if upd.Acceptid > 0 {
		email := users.GetUserEmail(upd.Acceptid)
		domain, _ := beego.AppConfig.String("domain")
		link := domain + "/view/taskEdit/" + fmt.Sprintf("%d", upd.Id)
		content := upd.Desc + "<br/><a href=\"" + link + "\">" + link + "</a>"
		go utils.SendMail(email, "新任务："+upd.Name, content)
	}
	//操作日志
	idpk := utils.SnowFlakeId()
	var log ProjectsTaskLog
	log.Id = idpk
	log.Userid = upd.Userid
	log.Taskid = upd.Id
	log.Status = task.Status
	log.Note = UserUsername + "创建了任务"
	log.Created = time.Now().Unix()
	err = AddTaskLog(log)
	return err
}

func UpdateTask(id int64, userid int64, UserUsername string, upd ProjectsTask) error {
	o := orm.NewOrm()
	task := ProjectsTask{Id: id}
	task.Changed = time.Now().Unix()
	var col []string
	col = append(col, "changed")
	if !utils.IsEmpty(upd.Needsid) {
		task.Needsid = upd.Needsid
		col = append(col, "needsid")
	}
	if !utils.IsEmpty(upd.Acceptid) {
		task.Acceptid = upd.Acceptid
		col = append(col, "acceptid")
	}
	if !utils.IsEmpty(upd.Name) {
		task.Name = upd.Name
		col = append(col, "name")
	}
	if !utils.IsEmpty(upd.Desc) {
		task.Desc = upd.Desc
		col = append(col, "desc")
	}
	if !utils.IsEmpty(upd.Level) {
		task.Level = upd.Level
		col = append(col, "level")
	}
	if !utils.IsEmpty(upd.Type) {
		task.Type = upd.Type
		col = append(col, "type")
	}
	if !utils.IsEmpty(upd.Tasktime) {
		task.Tasktime = upd.Tasktime
		col = append(col, "tasktime")
	}
	if !utils.IsEmpty(upd.Started) {
		task.Started = upd.Started
		col = append(col, "started")
	}
	if !utils.IsEmpty(upd.Ended) {
		task.Ended = upd.Ended
		col = append(col, "ended")
	}
	if !utils.IsEmpty(upd.Testid) {
		task.Testid = upd.Testid
		col = append(col, "testid")
	}
	if !utils.IsEmpty(upd.Moduleid) {
		task.Moduleid = upd.Moduleid
		col = append(col, "moduleid")
	}
	if !utils.IsEmpty(upd.Actualstarttime) {
		task.Actualstarttime = upd.Actualstarttime
		col = append(col, "actualstarttime")
	}
	if !utils.IsEmpty(upd.Actualendtime) {
		task.Actualendtime = upd.Actualendtime
		col = append(col, "actualendtime")
	}
	if !utils.IsEmpty(upd.Parenttaskid) {
		task.Parenttaskid = upd.Parenttaskid
		col = append(col, "parenttaskid")
	}
	if !utils.IsEmpty(upd.Acceptance) {
		task.Acceptance = upd.Acceptance
		col = append(col, "acceptance")
	}
	if !utils.IsEmpty(upd.Remaindertasktime) {
		task.Remaindertasktime = upd.Remaindertasktime
		col = append(col, "remaindertasktime")
	}
	if !utils.IsEmpty(upd.Stage) {
		task.Stage = upd.Stage
		col = append(col, "stage")
	}
	//1	TASK_STATUS	未开始
	//2	TASK_STATUS	进行中
	//3	TASK_STATUS	已完成
	//4	TASK_STATUS	已暂停
	//5	TASK_STATUS	已取消
	//6	TASK_STATUS	已关闭
	if !utils.IsEmpty(upd.Remaindertasktime) {
		task.Remaindertasktime = upd.Remaindertasktime
		if task.Remaindertasktime == 0 {
			task.Progress = 100
			task.Actualendtime = time.Now().Unix()
			task.Completeid = userid
			col = append(col, "progress", "actualendtime", "completeid")
		}
		col = append(col, "remaindertasktime")
	}
	if !utils.IsEmpty(upd.Status) {
		task.Status = upd.Status
		if task.Status == 3 {
			task.Progress = 100
			task.Actualendtime = time.Now().Unix()
			task.Completeid = userid
			col = append(col, "progress", "actualendtime", "completeid")
		} else if task.Status == 1 {
			task.Progress = 0
			task.Actualstarttime = time.Now().Unix()
			task.Actualendtime = 0
			task.Completeid = 0
			col = append(col, "progress", "actualstarttime", "actualendtime", "completeid")
		}
		col = append(col, "status")
	}
	if !utils.IsEmpty(upd.Progress) {
		task.Progress = upd.Progress
		if task.Progress >= 100 {
			task.Status = 3
			task.Actualendtime = time.Now().Unix()
			task.Completeid = userid
			col = append(col, "status", "actualendtime", "completeid")
		} else if task.Progress == 0 {
			task.Status = 1
			task.Actualstarttime = time.Now().Unix()
			task.Actualendtime = 0
			task.Completeid = 0
			col = append(col, "status", "actualstarttime", "actualendtime", "completeid")
		} else if task.Progress > 0 && task.Progress < 100 {
			task.Status = 2
			col = append(col, "status")
		}
		col = append(col, "progress")
	}
	if upd.Attachment != "" {
		task.Attachment = upd.Attachment
		col = append(col, "attachment")
	}
	_, err := o.Update(&task, utils.RemoveDuplicatesAndEmpty(col)...)
	//操作日志
	var log ProjectsTaskLog
	log.Id = utils.SnowFlakeId()
	log.Userid = userid //当前登录用户
	log.Taskid = id
	log.Status = task.Status
	log.Note = UserUsername + "编辑了任务"
	log.Created = time.Now().Unix()
	AddTaskLog(log)
	return err

}

func AddTaskLog(upd ProjectsTaskLog) error {
	o := orm.NewOrm()
	log := new(ProjectsTaskLog)
	log.Id = upd.Id
	log.Userid = upd.Userid
	log.Taskid = upd.Taskid
	log.Status = upd.Status
	log.Note = upd.Note
	log.Created = time.Now().Unix()
	_, err := o.Insert(log)
	return err
}

func GetProjectTask(id int64) (ProjectsTask, error) {
	var task ProjectsTask
	var err error
	o := orm.NewOrm()
	task = ProjectsTask{Id: id}
	err = o.Read(&task)
	if err == orm.ErrNoRows {
		return task, nil
	}
	return task, err
}

func ChangeProjectTaskStatus(id int64, userid int64, UserUsername string, status int) error {
	o := orm.NewOrm()
	task := ProjectsTask{Id: id}
	//1	TASK_STATUS	未开始
	//2	TASK_STATUS	进行中
	//3	TASK_STATUS	已完成
	//4	TASK_STATUS	已暂停
	//5	TASK_STATUS	已取消
	//6	TASK_STATUS	已关闭
	var col []string
	task.Status = status
	task.Changed = time.Now().Unix()
	col = append(col, "status", "changed")
	if 2 == status {
		task.Actualstarttime = time.Now().Unix()
		col = append(col, "actualstarttime")
	} else if 3 == status {
		task.Completeid = userid
		task.Actualendtime = time.Now().Unix()
		task.Progress = 100
		col = append(col, "progress", "completeid", "actualendtime")
	} else if 5 == status {
		task.Cancelid = userid
		task.Actualendtime = time.Now().Unix()
		col = append(col, "cancelid", "actualendtime")
	} else if 6 == status {
		task.Closeid = userid
		col = append(col, "closeid")
	}
	_, err := o.Update(&task, utils.RemoveDuplicatesAndEmpty(col)...)
	// 更新反馈 待设计
	//操作日志
	var log ProjectsTaskLog
	log.Id = utils.SnowFlakeId()
	log.Userid = userid
	log.Taskid = id
	log.Status = task.Status
	log.Note = UserUsername + "更改任务状态为" + dict.GetDictByTypeAndDictId_("TASK_STATUS", strconv.Itoa(status), task.Projectid).DictName
	log.Created = time.Now().Unix()
	err = AddTaskLog(log)
	return err
}

func ChangeProjectTaskAccept(userid int64, UserUsername string, u ProjectsTask) error {
	o := orm.NewOrm()
	task := ProjectsTask{Id: u.Id}
	task.Acceptid = u.Acceptid
	task.Changed = time.Now().Unix()
	_, err := o.Update(&task, "acceptid", "changed")
	if u.Acceptid > 0 {
		email := users.GetUserEmail(u.Acceptid)
		if email != "" {
			domain, _ := beego.AppConfig.String("domain")
			link := domain + "/view/task/show/" + fmt.Sprintf("%d", task.Id)
			content := task.Desc + "<br/><a href=\"" + link + "\">" + link + "</a>"
			go utils.SendMail(email, "新任务："+task.Name, content)
		}
	}
	//操作日志
	var log ProjectsTaskLog
	log.Id = utils.SnowFlakeId()
	log.Userid = userid
	log.Taskid = u.Id
	log.Status = task.Status
	log.Note = UserUsername + "指派给" + users.GetRealname(u.Acceptid) + "。"
	log.Created = time.Now().Unix()
	err = AddTaskLog(log)
	return err
}

/**
  删除任务
*/
func DeleteProjectTask(id int64) error {
	o := orm.NewOrm()
	to, err := o.Begin()
	_, err = to.Delete(&ProjectsTask{Id: id})
	if err != nil {
		to.Rollback()
		return err
	}
	_, err = to.Raw("DELETE FROM "+models.TableName("projects_task")+" WHERE taskid = ?", id).Exec()
	if err != nil {
		to.Rollback()
		return err
	}
	_, err = to.Raw("DELETE FROM "+models.TableName("projects_task_log")+" WHERE taskid = ?", id).Exec()
	if err != nil {
		to.Rollback()
		return err
	}
	_, err = to.Raw("DELETE FROM "+models.TableName("projects_task_comments")+" WHERE taskid = ?", id).Exec()
	if err != nil {
		to.Rollback()
		return err
	}
	to.Commit()
	return err
}

func TaskPageExec(condArr map[string]interface{}) (ops []ProjectsAllTask) {
	o := orm.NewOrm()
	o.Raw(taskPageSql(condArr)).QueryRows(&ops)
	return ops
}

/**
  组装sql
*/
func taskPageSql(condArr map[string]interface{}) (string, []interface{}) {
	var sql string
	sql = `
	SELECT
      ppt.taskid id,
      up4.name testname,
	  ppt.*,
	  pp.name AS projectname,
	  ppm.name AS modulename,
	  up.realname AS userrealname,
	  up1.realname AS acceptrealname,
	  up2.realname AS completerealname,
	  up3.positionid as positionid,
	  up3.name as positionname,
    ppn.name AS needsname
	FROM pms_projects_task  ppt
	  INNER JOIN pms_projects pp
		ON pp.projectid = ppt.projectid
	  LEFT JOIN pms_projects_module ppm
		ON ppm.moduleid = ppt.moduleid
	  INNER JOIN pms_users_profile up ON up.userid=ppt.userid
	  LEFT JOIN pms_users_profile up1 ON up1.userid=ppt.acceptid
	  LEFT JOIN pms_users_profile up2 ON up2.userid=ppt.completeid
	  LEFT JOIN pms_projects_test up4 ON up4.testid=ppt.testid
	  LEFT JOIN pms_positions up3 ON up1.positionid=up3.positionid
      LEFT JOIN pms_projects_needs ppn ON ppn.needsid=ppt.needsid
	WHERE 1 = 1 `
	param := make([]interface{}, 0, 0)
	if !utils.IsEmpty(condArr["projectid"]) {
		sql = sql + ` and  ppt.projectid=?`
		param = append(param, condArr["projectid"])
	}
	if !utils.IsEmpty(condArr["moduleid"]) {
		sql = sql + ` and  ppt.moduleid in(`
		sql1, value := cores.SqlInParam(condArr["moduleid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["userid"]) {
		sql = sql + ` and  ppt.userid in(`
		sql1, value := cores.SqlInParam(condArr["userid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if condArr["filter"] == "unaccept" {
		sql = sql + ` and  ppt.acceptid is null`
	} else if !utils.IsEmpty(condArr["acceptid"]) {
		sql = sql + ` and  ppt.acceptid in(`
		sql1, value := cores.SqlInParam(condArr["acceptid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["completeid"]) {
		sql = sql + ` and  ppt.completeid in(`
		sql1, value := cores.SqlInParam(condArr["completeid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["closeid"]) {
		sql = sql + ` and  ppt.closeid in(`
		sql1, value := cores.SqlInParam(condArr["closeid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["cancelid"]) {
		sql = sql + ` and  ppt.cancelid in(`
		sql1, value := cores.SqlInParam(condArr["cancelid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["level"]) {
		sql = sql + ` and  ppt.level in(`
		sql1, value := cores.SqlInParam(condArr["level"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["type"]) {
		sql = sql + ` and  ppt.type in(`
		sql1, value := cores.SqlInParam(condArr["type"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["source"]) {
		sql = sql + ` and  ppt.source in(`
		sql1, value := cores.SqlInParam(condArr["source"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["stage"]) {
		sql = sql + ` and  ppt.stage in(`
		sql1, value := cores.SqlInParam(condArr["stage"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["parenttaskid"]) {
		sql = sql + ` and  ppt.parenttaskid in(`
		sql1, value := cores.SqlInParam(condArr["parenttaskid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["status"]) {
		sql = sql + ` and  ppt.status in(`
		sql1, value := cores.SqlInParam(condArr["status"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["createStarted"]) {
		sql = sql + ` and  ppt.started >=?`
		param = append(param, condArr["createStartedint"])
	}
	if !utils.IsEmpty(condArr["createEnd"]) {
		sql = sql + ` and  ppt.ended <=?`
		param = append(param, condArr["createEndint"])
	}
	if !utils.IsEmpty(condArr["keywords"]) {
		sql = sql + ` and  ppt.name LIKE concat('%',?,'%')`
		param = append(param, condArr["keywords"])
	}
	if !utils.IsEmpty(condArr["taskid"]) {
		sql = sql + ` and  ppt.taskid LIKE concat('%',?,'%')`
		param = append(param, condArr["taskid"])
	}
	if !utils.IsEmpty(condArr["testid"]) {
		sql = sql + ` and  ppt.testid LIKE concat('%',?,'%')`
		param = append(param, condArr["testid"])
	}
	if !utils.IsEmpty(condArr["planid"]) {
		sql = sql + ` and  ppt.planid in(`
		sql1, value := cores.SqlInParam(condArr["planid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	if !utils.IsEmpty(condArr["classify"]) {
		sql = sql + ` and  ppt.classify =?`
		param = append(param, condArr["classify"])
	}
	sql = sql + ` order by ppt.orders asc  `
	return sql, param
}

func makeTree(Data *[]ProjectsAllTask) (node []ProjectsAllTask) { //参数为父节点，添加父节点的子节点指针切片
	for _, v := range *Data {
		cArr := make(map[string]interface{})
		cArr["parenttaskid"] = v.Id
		childs := TaskPageExec(cArr)
		relate, _ := GetTaskRelatedByTaskid(v.Id)
		v.Related = relate
		if childs != nil {
			v.Children = makeTree(&childs)
		}
		node = append(node, v)
	}
	return
}

// 上移任务
func upTask(o orm.TxOrmer, id int64, dto TaskOrderDto) error {
	sql := `update pms_projects_task set orders=orders+1 where taskid!=? and parenttaskid=? and  orders between ? and ? `
	_, err := o.Raw(sql, id, dto.Ptaskid, dto.Neworders, dto.Oldorders).Exec()
	return err
}

// 下移任务
func downTask(o orm.TxOrmer, id int64, dto TaskOrderDto) error {
	sql := `update pms_projects_task set orders=orders-1 where taskid!=? and parenttaskid=? and  orders between ? and ? `
	_, err := o.Raw(sql, id, dto.Ptaskid, dto.Oldorders, dto.Neworders).Exec()
	return err
}

// 下移任务
func updateTask(o orm.TxOrmer, id int64, dto TaskOrderDto) error {
	sql := `update pms_projects_task set orders=? where taskid=? `
	_, err := o.Raw(sql, dto.Neworders, id).Exec()
	return err
}

func taskMaxOrder(condArr ProjectsTask) int {
	o := orm.NewOrm()
	var maxOrder int
	sql := `select max(orders) from  pms_projects_task where parenttaskid=? and planid=? LIMIT 1 `
	err := o.Raw(sql, condArr.Parenttaskid, condArr.Planid).QueryRow(&maxOrder)
	logs.Info(err)
	return maxOrder
}

type TaskResource struct {
	Taskid            int64 `json:"Taksid,string"`
	Taskname          string
	Acceptrealname    string
	Acceptid          int64 `json:"Acceptid,string"`
	Level             int
	Tasktime          int
	Started           int64
	Ended             int64
	Progress          int
	Remaindertasktime int
	Positionid        int64
}

func TaskReourceExec(condArr map[string]interface{}) (ops []TaskResource) {
	o := orm.NewOrm()
	o.Raw(taskReourceSql(condArr)).QueryRows(&ops)
	return ops
}

/**
  组装sql 根据计划和项目获取  任务
*/
func taskReourceSql(condArr map[string]interface{}) (string, []interface{}) {
	var sql string
	sql = `
SELECT
    ppt.taskid,
    ppt.name taskname,
    ppt.acceptid,
    up1.realname AS acceptrealname,
    ppt.started,
    ppt.ended,
    ppt.tasktime,
    ppt.remaindertasktime,
    ppt.status,
    ppt.progress,
    ppt.level,
    pos.positionid positionid
	FROM pms_projects_task  ppt
	  INNER JOIN pms_projects pp
		ON pp.projectid = ppt.projectid
	  INNER JOIN pms_users_profile up1 ON up1.userid=ppt.acceptid
      INNER JOIN pms_positions pos ON pos.positionid=up1.positionid
	WHERE ppt.classify = 1 `
	param := make([]interface{}, 0, 0)
	if !utils.IsEmpty(condArr["projectid"]) {
		sql = sql + ` and  ppt.projectid=?`
		param = append(param, condArr["projectid"])
	}
	if !utils.IsEmpty(condArr["planid"]) {
		sql = sql + ` and  ppt.planid in (`
		sql1, value := cores.SqlInParam(condArr["planid"])
		sql = sql + sql1 + `)`
		param = append(param, value...)
	}
	return sql, param
}
